#include "Util.h"

class BaseException: public std::exception
{
public:
    BaseException()                             { fMessage = ""; }
    BaseException(string iMessage)              { fMessage = iMessage; }
    virtual const char* what() const throw ()   { return fMessage.c_str(); }
    virtual ~BaseException() throw()            { }

protected:
    string fMessage;
};

class DuplicateParameterNameException: public BaseException
{
public:
    DuplicateParameterNameException(string iFunctionName, string iVarName)
    {
        fMessage = "Funkce " + iFunctionName + ": duplicitni deklarace parametru " + iVarName + ".";
    }
};

class VariableNotDeclaredException: public BaseException
{
public:
    VariableNotDeclaredException(string iContainerName, string iVarName)
    {
        fMessage = iContainerName + ": promenna " + iVarName + " neni deklarovana.";
    }
};

class DuplicateVarDeclarationException: public BaseException
{
public:
    DuplicateVarDeclarationException(string iContainerName, string iVarName)
    {
        fMessage = iContainerName + ": promenna " + iVarName + " jiz byla deklarovana.";
    }
};

class UndefinedFunctionCallException: public BaseException
{
public:
    UndefinedFunctionCallException(string iContainerName, string iFuncName)
    {
        fMessage = iContainerName + ": funkce " + iFuncName + " neni definovana.";
    }

    UndefinedFunctionCallException(string iContainerName, string iFuncName, int iRequestedParamCount)
    {
        string lParamCount = Util::Number2String(iRequestedParamCount);
        fMessage = iContainerName + ": funkce " + iFuncName + " prijimajici " + lParamCount + " parametru neni definovana.";
    }
};

class UndeclaredClassInstantiationException: public BaseException
{
public:
    UndeclaredClassInstantiationException(string iContainerName, string iClassName)
    {
        fMessage = iContainerName + ": " + "trida " + iClassName + " neni deklarovana.";
    }
};

class NoConstructorAvailableException: public BaseException
{
public:
    NoConstructorAvailableException(string iContainerName, string iClassName)
    {
        fMessage = iContainerName + ": " + "trida " + iClassName + " nema zadny konstruktor.";
    }
    NoConstructorAvailableException(string iContainerName, string iClassName, int iRequestedParamCount)
    {
        string lParamCount = Util::Number2String(iRequestedParamCount);
        fMessage = iContainerName + ": " + "trida " + iClassName + " nema konstruktor prijimajici " + lParamCount + " parametru.";
    }
};

class AmbiguousFunctionDefinitionException: public BaseException
{
public:
    AmbiguousFunctionDefinitionException(string iFunctionName, int iParamCount)
    {
        string lParamCount = Util::Number2String(iParamCount);
        fMessage = "Funkce " + iFunctionName + " s poctem parametru " + lParamCount + " je nejednoznacne definovana.";
    }
};

class AmbiguousMethodDefinitionException: public BaseException
{
public:
    AmbiguousMethodDefinitionException(string iClassName, string iMethodName, int iParamCount)
    {
        string lParamCount = Util::Number2String(iParamCount);
        fMessage = "Metoda " + iClassName + "::" + iMethodName + " s poctem parametru " + lParamCount
                    + " je nejednoznacne definovana.";
    }
};

class AmbiguousClassDefinitionException: public BaseException
{
public:
    AmbiguousClassDefinitionException(string iClassName)
    {
        fMessage = "Trida " + iClassName + " jiz byla definovana.";
    }
};

class VariableIsNotAnObjectException: public BaseException
{
public:
    VariableIsNotAnObjectException(string iVarName, string iParentName)
    {
        fMessage = iParentName + ": promenna " + iVarName + " neni objekt.";
    }
};

class FieldNotDeclaredException: public BaseException
{
public:
    FieldNotDeclaredException(string iFieldName, string iVarName, string iParentName)
    {
        fMessage = iParentName + ": objekt odkazovany promennou " + iVarName + " nema polozku " + iFieldName + ".";
    }
};

class MethodNotDeclaredException: public BaseException
{
public:
    MethodNotDeclaredException(string iMethodName, string iVarName, int iParamCount, string iParentName)
    {
        fMessage = iParentName + ": objekt odkazovany promennou " + iVarName + " nema metodu " + iMethodName
            + " s poctem parametru " + Util::Number2String(iParamCount)  + ".";
    }
};

class InvalidTypeException: public BaseException
{
public:
    InvalidTypeException(string iParentName, string iAdditionalInfo, ValueType iExpected, ValueType iGot)
    {
        fMessage = iParentName + ": " + iAdditionalInfo + ": neplatny typ; ocekavano: " + Util::ValueType2String(iExpected)
            + "; nalezeno: " + Util::ValueType2String(iGot);
    }
};

class CallWithoutReturnException: public BaseException
{
public:
    CallWithoutReturnException(string iParentName, string iFunctionName, bool iIsFunctionCall)
    {
        fMessage = iParentName + ": " + (iIsFunctionCall ? "funkce" : "metoda") + " " + iFunctionName + " se vraci bez hodnoty.";
    }
};

class IncompatibleOperationAndTypesException: public BaseException
{
public:
    IncompatibleOperationAndTypesException(string iParentName, ValueType iFirst, ValueType iSecond, BinaryOperationType iOp)
    {
        fMessage = iParentName + ": operace '" + Util::BinaryOp2String(iOp) + "': nespravne typy: "
            + Util::ValueType2String(iFirst) + ", " + Util::ValueType2String(iSecond) + ".";
    }
};

class InvalidUnaryOpExprTypeException: public BaseException
{
public:
    InvalidUnaryOpExprTypeException(string iParentName, ValueType iGot, UnaryOperationType iOp)
    {
        fMessage = iParentName + ": unarni operace " + Util::UnaryOp2String(iOp) + ": nespravny typ vyrazu: "
            + Util::ValueType2String(iGot) + ".";
    }
};

class BaseClassUndefinedException: public BaseException
{
public:
    BaseClassUndefinedException(string iClassName, string iParentClassName)
    {
        fMessage = "Trida '" + iClassName + "': rodicovska trida '" + iParentClassName + "' neni definovana.";
    }
};

class FieldOverloadingException: public BaseException
{
public:
    FieldOverloadingException(string iClassName, string iParentClassName, string iFieldName)
    {
        fMessage = "Trida '" + iClassName + "': polozka '" + iFieldName + "' byla zdedena od '" + iParentClassName
            + "', neni mozne ji pretizit.";
    }
};

class InheritedMethodConflictException: public BaseException
{
public:
    InheritedMethodConflictException(string iClassName, string iMethodName, string iParentClass1, string iParentClass2)
    {
        fMessage = "Trida '" + iClassName + "': metoda '" + iMethodName + "' je nejednoznacne zdedena od '"
            + iParentClass1 + "' a '" + iParentClass2 + "'.";
    }
};

class InheritedFieldConflictException: public BaseException
{
public:
    InheritedFieldConflictException(string iClassName, string iFieldName, string iParentClass1, string iParentClass2)
    {
        fMessage = "Trida '" + iClassName + "': polozka '" + iFieldName + "' je nejednoznacne zdedena od '"
            + iParentClass1 + "' a '" + iParentClass2 + "'.";
    }
};

class MainFunctionNotDefinedException: public BaseException
{
public:
    MainFunctionNotDefinedException()
    {
        fMessage = "Funkce main() neni definovana.";
    }
};

class FunctionCallWithWrongParamCountException: public BaseException
{
public:
    FunctionCallWithWrongParamCountException(string iFunctionName, int iRequestedParamCount, int iActualParamCount)
    {
        fMessage = "Volani funkce '" + iFunctionName + "': pozadovano " + Util::Number2String(iRequestedParamCount)
            + " parametru, obdrzeno " + Util::Number2String(iActualParamCount) + ".";
    }
};

class BadTypeToPrintException: public BaseException
{
public:
    BadTypeToPrintException(ValueType iType, string iParentName)
    {
        fMessage = iParentName + ": typ '" + Util::ValueType2String(iType) + " nemuze byt vytisten.";
    }
};

class VariableIsNotAnArrayException: public BaseException
{
public:
    VariableIsNotAnArrayException(string iVarName, string iParentName)
    {
        fMessage = iParentName + ": promenna " + iVarName + " neni pole.";
    }
};

class InvalidIndexTypeException: public BaseException
{
public:
    InvalidIndexTypeException(string iParentName, ValueType iType)
    {
        fMessage = iParentName + ": pristup k poli: index je spatneho typu; ocekavan int, double nebo string,"
            + " nalezeno " + Util::ValueType2String(iType);
    }
};

class TooMuchCallParamCount: public BaseException
{
public:
    TooMuchCallParamCount(string iParentName, string iCalleeName, int iMaxCount, int iActualCount)
    {
        fMessage = iParentName + ": volani '" + iCalleeName + "': prilis mnoho parametru; obdrzeno: "
            + Util::Number2String(iActualCount) + "; maximum: " + Util::Number2String(iMaxCount) + ".";
    }
};

class TooMuchLocalVars: public BaseException
{
public:
    TooMuchLocalVars(string iParentName, int iMaxCount, int iActualCount)
    {
        fMessage = iParentName + ": je povoleno maximalne " + Util::Number2String(iMaxCount)
            + " lokalnich promennych vcetne parametru;" + " obdrzeno: " + Util::Number2String(iActualCount) + ".";
    }
};

class UnsupportedBinaryOperationType: public BaseException
{
public:
    UnsupportedBinaryOperationType(BinaryOperationType iOp)
    {
        fMessage = "Operaci '" + Util::BinaryOp2String(iOp) + "' nelze prelozit.";
    }
};

class UnsupportedConstantValueType: public BaseException
{
public:
    UnsupportedConstantValueType(ValueType iType)
    {
        fMessage = "Konstantu typu '" + Util::ValueType2String(iType) + "' nelze prelozit.";
    }
};

class UnsupportedUnaryOperationType: public BaseException
{
public:
    UnsupportedUnaryOperationType(UnaryOperationType iOp)
    {
        fMessage = "Operaci '" + Util::UnaryOp2String(iOp) + "' nelze prelozit.";
    }
};

; // na ten strednik pozor